home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / romcmp.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  15KB  |  693 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "unzip.h"
  5. #include "osdepend.h"    /* for CLIB_DECL */
  6. #include <stdarg.h>
  7. #ifdef macintosh    /* JB 981117 */
  8. #    include "mac_dos.h"
  9. #    include "stat.h"
  10. #else
  11. #include <dirent.h>
  12. #include <sys/stat.h>
  13. #include <sys/errno.h>
  14. #endif
  15.  
  16.  
  17. #define MAX_FILES 100
  18.  
  19. #ifdef macintosh    /* JB 981117 */
  20.  
  21. static int errno = 0;
  22. #define MAX_FILENAME_LEN 31
  23.  
  24. #else
  25. #define MAX_FILENAME_LEN 12    /* increase this if you are using a real OS... */
  26. #endif
  27.  
  28.  
  29. /* for unzip.c */
  30. void CLIB_DECL logerror(const char *text,...)
  31. {
  32. }
  33.  
  34.  
  35. /* compare modes when one file is twice as long as the other */
  36. /* A = All file */
  37. /* 1 = 1st half */
  38. /* 2 = 2nd half */
  39. /* E = Even bytes */
  40. /* O = Odd butes */
  41. /* E1 = Even bytes 1st half */
  42. /* O1 = Odd butes 1st half */
  43. /* E2 = Even bytes 2nd half */
  44. /* O2 = Odd butes 2nd half */
  45. enum {    MODE_A_A, MODE_12_A, MODE_22_A, MODE_E_A, MODE_O_A,
  46.                   MODE_14_A, MODE_24_A, MODE_34_A, MODE_44_A,
  47.                   MODE_E1_A, MODE_O1_A, MODE_E2_A, MODE_O2_A,
  48.                   MODE_A_12, MODE_A_22, MODE_A_E, MODE_A_O,
  49.                   MODE_A_14, MODE_A_24, MODE_A_34, MODE_A_44,
  50.                   MODE_A_E1, MODE_A_O1, MODE_A_E2, MODE_A_O2,
  51.         TOTAL_MODES };
  52. char *modenames[][2] =
  53. {
  54.     { "          ", "          " },
  55.     { "[1/2]     ", "          " },
  56.     { "[2/2]     ", "          " },
  57.     { "[even]    ", "          " },
  58.     { "[odd]     ", "          " },
  59.     { "[1/4]     ", "          " },
  60.     { "[2/4]     ", "          " },
  61.     { "[3/4]     ", "          " },
  62.     { "[4/4]     ", "          " },
  63.     { "[even 1/2]", "          " },
  64.     { "[odd 1/2] ", "          " },
  65.     { "[even 2/2]", "          " },
  66.     { "[odd 2/2] ", "          " },
  67.     { "          ", "[1/2]     " },
  68.     { "          ", "[2/2]     " },
  69.     { "          ", "[even]    " },
  70.     { "          ", "[odd]     " },
  71.     { "          ", "[1/4]     " },
  72.     { "          ", "[2/4]     " },
  73.     { "          ", "[3/4]     " },
  74.     { "          ", "[4/4]     " },
  75.     { "          ", "[even 1/2]" },
  76.     { "          ", "[odd 1/2] " },
  77.     { "          ", "[even 2/2]" },
  78.     { "          ", "[odd 2/2] " }
  79. };
  80.  
  81. struct fileinfo
  82. {
  83.     char name[MAX_FILENAME_LEN+1];
  84.     int size;
  85.     unsigned char *buf;    /* file is read in here */
  86.     int listed;
  87. };
  88.  
  89. struct fileinfo files[2][MAX_FILES];
  90. float matchscore[MAX_FILES][MAX_FILES][TOTAL_MODES];
  91.  
  92.  
  93. static void checkintegrity(const struct fileinfo *file,int side)
  94. {
  95.     int i;
  96.     int mask0,mask1;
  97.     int addrbit;
  98.  
  99.  
  100.     if (file->buf == 0) return;
  101.  
  102.  
  103.  
  104.     /* check for bad data lines */
  105.     mask0 = 0x0000;
  106.     mask1 = 0xffff;
  107.  
  108.     for (i = 0;i < file->size;i+=2)
  109.     {
  110.         mask0 |= ((file->buf[i] << 8) | file->buf[i+1]);
  111.         mask1 &= ((file->buf[i] << 8) | file->buf[i+1]);
  112.         if (mask0 == 0xffff && mask1 == 0x0000) break;
  113.     }
  114.  
  115.     if (mask0 != 0xffff || mask1 != 0x0000)
  116.     {
  117.         int fixedmask;
  118.         int bits;
  119.  
  120.  
  121.         fixedmask = (~mask0 | mask1) & 0xffff;
  122.  
  123.         if (((mask0 >> 8) & 0xff) == (mask0 & 0xff) && ((mask1 >> 8) & 0xff) == (mask1 & 0xff))
  124.             bits = 8;
  125.         else bits = 16;
  126.  
  127.         printf("%-23s %-23s FIXED BITS (",side ? "" : file->name,side ? file->name : "");
  128.         for (i = 0;i < bits;i++)
  129.         {
  130.             if (~mask0 & 0x8000) printf("0");
  131.             else if (mask1 & 0x8000) printf("1");
  132.             else printf("x");
  133.  
  134.             mask0 <<= 1;
  135.             mask1 <<= 1;
  136.         }
  137.         printf(")\n");
  138.  
  139.         /* if the file contains a fixed value, we don't need to do the other */
  140.         /* validity checks */
  141.         if (fixedmask == 0xffff || fixedmask == 0x00ff || fixedmask == 0xff00)
  142.             return;
  143.     }
  144.  
  145.  
  146.     addrbit = 1;
  147.     mask0 = 0;
  148.     while (addrbit <= file->size/2)
  149.     {
  150.         for (i = 0;i < file->size;i++)
  151.         {
  152.             if (file->buf[i] != file->buf[i ^ addrbit]) break;
  153.         }
  154.  
  155.         if (i == file->size)
  156.             mask0 |= addrbit;
  157.  
  158.         addrbit <<= 1;
  159.     }
  160.  
  161.     if (mask0)
  162.     {
  163.         if (mask0 == file->size/2)
  164.             printf("%-23s %-23s FIRST AND SECOND HALF IDENTICAL\n",side ? "" : file->name,side ? file->name : "");
  165.         else
  166.             printf("%-23s %-23s BAD ADDRESS LINES (mask=%06x)\n",side ? "" : file->name,side ? file->name : "",mask0);
  167.         return;
  168.     }
  169.  
  170.     mask0 = 0x000000;
  171.     mask1 = file->size-1;
  172.     for (i = 0;i < file->size;i++)
  173.     {
  174.         if (file->buf[i] != 0xff)
  175.         {
  176.             mask0 |= i;
  177.             mask1 &= i;
  178.             if (mask0 == file->size-1 && mask1 == 0x00) break;
  179.         }
  180.     }
  181.  
  182.     if (mask0 != file->size-1 || mask1 != 0x00)
  183.     {
  184.         printf("%-23s %-23s ",side ? "" : file->name,side ? file->name : "");
  185.         for (i = 0;i < 24;i++)
  186.         {
  187.             if (file->size <= (1<<(23-i))) printf(" ");
  188.             else if (~mask0 & 0x800000) printf("1");
  189.             else if (mask1 & 0x800000) printf("0");
  190.             else printf("x");
  191.             mask0 <<= 1;
  192.             mask1 <<= 1;
  193.         }
  194.         printf(" = 0xFF\n");
  195.  
  196.         return;
  197.     }
  198.  
  199.  
  200.     mask0 = 0x000000;
  201.     mask1 = file->size-1;
  202.     for (i = 0;i < file->size;i++)
  203.     {
  204.         if (file->buf[i] != 0x00)
  205.         {
  206.             mask0 |= i;
  207.             mask1 &= i;
  208.             if (mask0 == file->size-1 && mask1 == 0x00) break;
  209.         }
  210.     }
  211.  
  212.     if (mask0 != file->size-1 || mask1 != 0x00)
  213.     {
  214.         printf("%-23s %-23s ",side ? "" : file->name,side ? file->name : "");
  215.         for (i = 0;i < 24;i++)
  216.         {
  217.             if (file->size <= (1<<(23-i))) printf(" ");
  218.             else if ((mask0 & 0x800000) == 0) printf("1");
  219.             else if (mask1 & 0x800000) printf("0");
  220.             else printf("x");
  221.             mask0 <<= 1;
  222.             mask1 <<= 1;
  223.         }
  224.         printf(" = 0x00\n");
  225.  
  226.         return;
  227.     }
  228.  
  229.  
  230.     for (i = 0;i < file->size/4;i++)
  231.     {
  232.         if (file->buf[file->size/2 + 2*i+1] != 0xff) break;
  233.         if (file->buf[2*i+1] != file->buf[file->size/2 + 2*i]) break;
  234.     }
  235.  
  236.     if (i == file->size/4)
  237.         printf("%-23s %-23s BAD NEOGEO DUMP - CUT 2ND HALF\n",side ? "" : file->name,side ? file->name : "");
  238. }
  239.  
  240.  
  241. static float filecompare(const struct fileinfo *file1,const struct fileinfo *file2,int mode)
  242. {
  243.     int i;
  244.     int match = 0;
  245.     float score = 0.0;
  246.  
  247.  
  248.     if (file1->buf == 0 || file2->buf == 0) return 0.0;
  249.  
  250.     if (mode >= MODE_A_12 && mode <= MODE_A_O2)
  251.     {
  252.         const struct fileinfo *temp;
  253.         mode -= MODE_A_O2 - MODE_A_12 + 1;
  254.  
  255.         temp = file1;
  256.         file1 = file2;
  257.         file2 = temp;
  258.     }
  259.  
  260.     if (mode == MODE_A_A)
  261.     {
  262.         if (file1->size != file2->size) return 0.0;
  263.     }
  264.     else if (mode >= MODE_12_A && mode <= MODE_O_A)
  265.     {
  266.         if (file1->size != 2*file2->size) return 0.0;
  267.     }
  268.     else if (mode >= MODE_14_A && mode <= MODE_O2_A)
  269.     {
  270.         if (file1->size != 4*file2->size) return 0.0;
  271.     }
  272.  
  273.     switch (mode)
  274.     {
  275.         case MODE_A_A:
  276.         case MODE_12_A:
  277.         case MODE_14_A:
  278.             for (i = 0;i < file2->size;i++)
  279.             {
  280.                 if (file1->buf[i] == file2->buf[i]) match++;
  281.             }
  282.             score = (float)match/file2->size;
  283.             break;
  284.  
  285.         case MODE_22_A:
  286.         case MODE_24_A:
  287.             for (i = 0;i < file2->size;i++)
  288.             {
  289.                 if (file1->buf[i + file2->size] == file2->buf[i]) match++;
  290.             }
  291.             score = (float)match/file2->size;
  292.             break;
  293.  
  294.         case MODE_34_A:
  295.             for (i = 0;i < file2->size;i++)
  296.             {
  297.                 if (file1->buf[i + 2*file2->size] == file2->buf[i]) match++;
  298.             }
  299.             score = (float)match/file2->size;
  300.             break;
  301.  
  302.         case MODE_44_A:
  303.             for (i = 0;i < file2->size;i++)
  304.             {
  305.                 if (file1->buf[i + 3*file2->size] == file2->buf[i]) match++;
  306.             }
  307.             score = (float)match/file2->size;
  308.             break;
  309.  
  310.         case MODE_E_A:
  311.         case MODE_E1_A:
  312.             for (i = 0;i < file2->size;i++)
  313.             {
  314.                 if (file1->buf[2*i] == file2->buf[i]) match++;
  315.             }
  316.             score = (float)match/file2->size;
  317.             break;
  318.  
  319.         case MODE_O_A:
  320.         case MODE_O1_A:
  321.             for (i = 0;i < file2->size;i++)
  322.             {
  323.                 if (file1->buf[2*i+1] == file2->buf[i]) match++;
  324.             }
  325.             score = (float)match/file2->size;
  326.             break;
  327.  
  328.         case MODE_E2_A:
  329.             for (i = 0;i < file2->size;i++)
  330.             {
  331.                 if (file1->buf[2*i + 2*file2->size] == file2->buf[i]) match++;
  332.             }
  333.             score = (float)match/file2->size;
  334.             break;
  335.  
  336.         case MODE_O2_A:
  337.             for (i = 0;i < file2->size;i++)
  338.             {
  339.                 if (file1->buf[2*i+1 + 2*file2->size] == file2->buf[i]) match++;
  340.             }
  341.             score = (float)match/file2->size;
  342.             break;
  343.     }
  344.  
  345.     return score;
  346. }
  347.  
  348.  
  349. static void readfile(const char *path,struct fileinfo *file)
  350. {
  351.     char fullname[256];
  352.     FILE *f = 0;
  353.  
  354.  
  355.     if (path)
  356.     {
  357.         strcpy(fullname,path);
  358. #ifdef macintosh    /* JB 981117 */
  359.         strcat(fullname,":");
  360. #else
  361.         strcat(fullname,"/");
  362. #endif
  363.     }
  364.     else fullname[0] = 0;
  365.     strcat(fullname,file->name);
  366.  
  367.     if ((file->buf = malloc(file->size)) == 0)
  368.     {
  369.         printf("%s: out of memory!\n",file->name);
  370.         return;
  371.     }
  372.  
  373.     if ((f = fopen(fullname,"rb")) == 0)
  374.     {
  375. #ifdef macintosh    /* JB 981117 */
  376.         errno = fnfErr;
  377. #endif
  378.         printf("%s: %s\n",fullname,strerror(errno));
  379.         return;
  380.     }
  381.  
  382.     if (fread(file->buf,1,file->size,f) != file->size)
  383.     {
  384. #ifdef macintosh    /* JB 981117 */
  385.         errno = fnfErr;
  386. #endif
  387.         printf("%s: %s\n",fullname,strerror(errno));
  388.         fclose(f);
  389.         return;
  390.     }
  391.  
  392.     fclose(f);
  393.  
  394.     return;
  395. }
  396.  
  397.  
  398. static void freefile(struct fileinfo *file)
  399. {
  400.     free(file->buf);
  401.     file->buf = 0;
  402. }
  403.  
  404.  
  405. static void printname(const struct fileinfo *file1,const struct fileinfo *file2,float score,int mode)
  406. {
  407.     printf("%-12s %s %-12s %s ",file1 ? file1->name : "",modenames[mode][0],file2 ? file2->name : "",modenames[mode][1]);
  408.     if (score == 0.0) printf("NO MATCH\n");
  409.     else if (score == 1.0) printf("IDENTICAL\n");
  410.     else printf("%3.3f%%\n",score*100);
  411. }
  412.  
  413.  
  414. static int load_files(int i, int *found, const char *path)
  415. {
  416.     struct stat st;
  417.  
  418.  
  419.     if (stat(path,&st) != 0)
  420.     {
  421. #ifdef macintosh
  422.         errno = fnfErr;
  423. #endif
  424.         printf("%s: %s\n",path,strerror(errno));
  425.         return 10;
  426.     }
  427.  
  428.     if (S_ISDIR(st.st_mode))
  429.     {
  430.         DIR *dir;
  431.         struct dirent *d;
  432.  
  433.         /* load all files in directory */
  434.         dir = opendir(path);
  435.         if (dir)
  436.         {
  437.             while((d = readdir(dir)) != NULL)
  438.             {
  439.                 char buf[255+1];
  440.                 struct stat st_file;
  441.  
  442.                 sprintf(buf, "%s/%s", path, d->d_name);
  443.                 if(stat(buf, &st_file) == 0 && S_ISREG(st_file.st_mode))
  444.                 {
  445.                     unsigned size = st_file.st_size;
  446.                     while (size && (size & 1) == 0) size >>= 1;
  447.                     if (size & ~1)
  448.                         printf("%-23s %-23s ignored (not a ROM)\n",i ? "" : d->d_name,i ? d->d_name : "");
  449.                     else
  450.                     {
  451.                         strcpy(files[i][found[i]].name,d->d_name);
  452.                         files[i][found[i]].size = st_file.st_size;
  453.                         readfile(path,&files[i][found[i]]);
  454.                         files[i][found[i]].listed = 0;
  455.                         if (found[i] >= MAX_FILES)
  456.                         {
  457.                             printf("%s: max of %d files exceeded\n",path,MAX_FILES);
  458.                             break;
  459.                         }
  460.                         found[i]++;
  461.                     }
  462.                 }
  463.             }
  464.             closedir(dir);
  465.         }
  466.     }
  467.     else
  468.     {
  469.         ZIP *zip;
  470.         struct zipent* zipent;
  471.  
  472.         /* wasn't a directory, so try to open it as a zip file */
  473.         if ((zip = openzip(path)) == 0)
  474.         {
  475.             printf("Error, cannot open zip file '%s' !\n", path);
  476.             return 1;
  477.         }
  478.  
  479.         /* load all files in zip file */
  480.         while ((zipent = readzip(zip)) != 0)
  481.         {
  482.             int size;
  483.  
  484.             size = zipent->uncompressed_size;
  485.             while (size && (size & 1) == 0) size >>= 1;
  486.             if (zipent->uncompressed_size == 0 || (size & ~1))
  487.                 printf("%-23s %-23s ignored (not a ROM)\n",
  488.                     i ? "" : zipent->name, i ? zipent->name : "");
  489.             else
  490.             {
  491.                 struct fileinfo *file = &files[i][found[i]];
  492.                 const char *delim = strrchr(zipent->name,'/');
  493.  
  494.                 if (delim)
  495.                     strcpy (file->name,delim+1);
  496.                 else
  497.                     strcpy(file->name,zipent->name);
  498.                 file->size = zipent->uncompressed_size;
  499.                 if ((file->buf = malloc(file->size)) == 0)
  500.                     printf("%s: out of memory!\n",file->name);
  501.                 else
  502.                 {
  503.                     if (readuncompresszip(zip, zipent, (char *)file->buf) != 0)
  504.                     {
  505.                         free(file->buf);
  506.                         file->buf = 0;
  507.                     }
  508.                 }
  509.  
  510.                 file->listed = 0;
  511.                 if (found[i] >= MAX_FILES)
  512.                 {
  513.                     printf("%s: max of %d files exceeded\n",path,MAX_FILES);
  514.                     break;
  515.                 }
  516.                 found[i]++;
  517.             }
  518.         }
  519.         closezip(zip);
  520.     }
  521.     return 0;
  522. }
  523.  
  524.  
  525. int main(int argc,char **argv)
  526. {
  527.     int    err;
  528.  
  529.     if (argc < 2)
  530.     {
  531.         printf("usage: romcmp [dir1 | zip1] [dir2 | zip2]\n");
  532.         return 0;
  533.     }
  534.  
  535.     {
  536.         int found[2];
  537.         int i,j,mode;
  538.         int besti,bestj;
  539.  
  540.  
  541.         found[0] = found[1] = 0;
  542.         for (i = 0;i < 2;i++)
  543.         {
  544.             if (argc > i+1)
  545.             {
  546.                 err = load_files (i, found, argv[i+1]);
  547.                 if (err != 0)
  548.                     return err;
  549.             }
  550.         }
  551.  
  552.         if (argc >= 3)
  553.             printf("%d and %d files\n",found[0],found[1]);
  554.         else
  555.             printf("%d files\n",found[0]);
  556.  
  557.         for (i = 0;i < found[0];i++)
  558.         {
  559.             checkintegrity(&files[0][i],0);
  560.         }
  561.  
  562.         for (j = 0;j < found[1];j++)
  563.         {
  564.             checkintegrity(&files[1][j],1);
  565.         }
  566.  
  567.         if (argc < 3)
  568.         {
  569.             /* find duplicates in one dir */
  570.             for (i = 0;i < found[0];i++)
  571.             {
  572.                 for (j = i+1;j < found[0];j++)
  573.                 {
  574.                     for (mode = 0;mode < TOTAL_MODES;mode++)
  575.                     {
  576.                         if (filecompare(&files[0][i],&files[0][j],mode) == 1.0)
  577.                             printname(&files[0][i],&files[0][j],1.0,mode);
  578.                     }
  579.                 }
  580.             }
  581.         }
  582.         else
  583.         {
  584.             /* compare two dirs */
  585.             for (i = 0;i < found[0];i++)
  586.             {
  587.                 for (j = 0;j < found[1];j++)
  588.                 {
  589.                     for (mode = 0;mode < TOTAL_MODES;mode++)
  590.                     {
  591.                         matchscore[i][j][mode] = filecompare(&files[0][i],&files[1][j],mode);
  592.                     }
  593.                 }
  594.             }
  595.  
  596.             do
  597.             {
  598.                 float bestscore;
  599.                 int bestmode;
  600.  
  601.                 besti = -1;
  602.                 bestj = -1;
  603.                 bestscore = 0.0;
  604.                 bestmode = -1;
  605.  
  606.                 for (mode = 0;mode < TOTAL_MODES;mode++)
  607.                 {
  608.                     for (i = 0;i < found[0];i++)
  609.                     {
  610.                         for (j = 0;j < found[1];j++)
  611.                         {
  612.                             if (matchscore[i][j][mode] > bestscore)
  613.                             {
  614.                                 bestscore = matchscore[i][j][mode];
  615.                                 besti = i;
  616.                                 bestj = j;
  617.                                 bestmode = mode;
  618.                             }
  619.                         }
  620.                     }
  621.                 }
  622.  
  623.                 if (besti != -1)
  624.                 {
  625.                     printname(&files[0][besti],&files[1][bestj],bestscore,bestmode);
  626.                     files[0][besti].listed = 1;
  627.                     files[1][bestj].listed = 1;
  628.  
  629.                     matchscore[besti][bestj][bestmode] = 0.0;
  630.                     for (mode = 0;mode < TOTAL_MODES;mode++)
  631.                     {
  632.                         if (bestmode == MODE_A_A || mode == bestmode ||
  633.                                 (bestmode >= MODE_12_A && bestmode <= MODE_O_A &&
  634.                                 ((mode-MODE_12_A)&~1) != ((bestmode-MODE_12_A)&~1)) ||
  635.                                 (bestmode >= MODE_14_A && bestmode <= MODE_44_A &&
  636.                                 ((mode-MODE_14_A)&~3) != ((bestmode-MODE_14_A)&~3)) ||
  637.                                 (bestmode >= MODE_E1_A && bestmode <= MODE_O2_A &&
  638.                                 ((mode-MODE_E1_A)&~3) != ((bestmode-MODE_E1_A)&~3)) ||
  639.                                 (bestmode >= MODE_A_12 && bestmode <= MODE_A_O &&
  640.                                 ((mode-MODE_A_12)&~1) != ((bestmode-MODE_A_12)&~1)) ||
  641.                                 (bestmode >= MODE_A_14 && bestmode <= MODE_A_44 &&
  642.                                 ((mode-MODE_A_14)&~3) != ((bestmode-MODE_A_14)&~3)) ||
  643.                                 (bestmode >= MODE_A_E1 && bestmode <= MODE_A_O2 &&
  644.                                 ((mode-MODE_A_E1)&~3) != ((bestmode-MODE_A_E1)&~3)))
  645.                         {
  646.                             for (i = 0;i < found[0];i++)
  647.                             {
  648.                                 if (matchscore[i][bestj][mode] < bestscore)
  649.                                     matchscore[i][bestj][mode] = 0.0;
  650.                             }
  651.                             for (j = 0;j < found[1];j++)
  652.                             {
  653.                                 if (matchscore[besti][j][mode] < bestscore)
  654.                                     matchscore[besti][j][mode] = 0.0;
  655.                             }
  656.                         }
  657.                         if (files[0][besti].size > files[1][bestj].size)
  658.                         {
  659.                             for (i = 0;i < found[0];i++)
  660.                             {
  661.                                 if (matchscore[i][bestj][mode] < bestscore)
  662.                                     matchscore[i][bestj][mode] = 0.0;
  663.                             }
  664.                         }
  665.                         else
  666.                         {
  667.                             for (j = 0;j < found[1];j++)
  668.                             {
  669.                                 if (matchscore[besti][j][mode] < bestscore)
  670.                                     matchscore[besti][j][mode] = 0.0;
  671.                             }
  672.                         }
  673.                     }
  674.                 }
  675.             } while (besti != -1);
  676.  
  677.  
  678.             for (i = 0;i < found[0];i++)
  679.             {
  680.                 if (files[0][i].listed == 0) printname(&files[0][i],0,0.0,0);
  681.                 freefile(&files[0][i]);
  682.             }
  683.             for (i = 0;i < found[1];i++)
  684.             {
  685.                 if (files[1][i].listed == 0) printname(0,&files[1][i],0.0,0);
  686.                 freefile(&files[1][i]);
  687.             }
  688.         }
  689.     }
  690.  
  691.     return 0;
  692. }
  693.